/*
 * Copyright By ZATI
 * Copyright By 3a3c88295d37870dfd3b25056092d1a9209824b256c341f2cdc296437f671617
 * All rights reserved.
 *
 * If you are not the intended user, you are hereby notified that any use, disclosure, copying, printing, forwarding or
 * dissemination of this property is strictly prohibited. If you have got this file in error, delete it from your system.
 */

package cn.wzc.crystal.security.service;

import cn.wzc.crystal.iam.entity.IamPerm;
import cn.wzc.crystal.iam.entity.IamRole;
import cn.wzc.crystal.iam.entity.IamUser;
import cn.wzc.crystal.iam.repository.PermRepository;
import cn.wzc.crystal.iam.repository.RoleRepository;
import cn.wzc.crystal.iam.repository.UserRepository;
import cn.wzc.crystal.platform.service.TimeService;
import cn.wzc.crystal.security.code.SecurityCode;
import cn.wzc.crystal.security.config.SecurityProperties;
import cn.wzc.crystal.security.vo.LoginInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AuthService implements UserDetailsService {

	private final TimeService timeService;

	private final RoleRepository roleRepository;
	private final PermRepository permRepository;
	private final UserRepository userRepository;

	private final PasswordEncoder passwordEncoder;
	private final SecurityProperties securityProperties;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 如果是超级用户
		// 则直接赋予所有权限,所有角色
		if (this.isSuperUser(username)) {
			// 超级管理员的权限
			List<SimpleGrantedAuthority> authorities = new ArrayList<>();

			// 授权所有 角色
			for (IamRole iamRole : roleRepository.findAll()) {
				authorities.add(new SimpleGrantedAuthority("ROLE_" + iamRole.getRoleCode()));
			}

			// 授权所有 权限
			for (IamPerm iamPerm : permRepository.findAll()) {
				if (iamPerm.isAuthority()) {
					authorities.add(new SimpleGrantedAuthority(iamPerm.getPermCode()));
				}
			}

			// 组装用户对象
			return User.withUsername(username)
				.disabled(false)
				.accountExpired(false)
				.accountLocked(false)
				.credentialsExpired(false)
				.password(passwordEncoder.encode(securityProperties.getSuperPassword()))
				.authorities(authorities)
				.build();
		}

		// 普通用户
		final IamUser iamUser = userRepository.findByUserName(username);

		//  没有这个用户
		if (null == iamUser) {
			throw new UsernameNotFoundException(SecurityCode.BAD_CREDENTIALS.getMessage());
		}

		// 超级管理员的权限
		List<SimpleGrantedAuthority> authorities = new ArrayList<>();

		// 授权所有 角色
		for (IamRole iamRole : roleRepository.queryByUser(iamUser.getId())) {
			authorities.add(new SimpleGrantedAuthority("ROLE_" + iamRole.getRoleCode()));
		}

		// 授权所有 权限
		for (IamPerm iamPerm : permRepository.queryByUser(iamUser.getId())) {
			if (iamPerm.isAuthority()) {
				authorities.add(new SimpleGrantedAuthority(iamPerm.getPermCode()));
			}
		}


		// 组装用户对象
		return User.withUsername(username)
			.disabled(false)
			.accountExpired(false)
			.accountLocked(false)
			.credentialsExpired(false)
			.password(iamUser.getUserPassword())
			.authorities(authorities)
			.build();
	}


	/**
	 * 构建登录信息
	 *
	 * @param username 用户名
	 * @param clientIp 登录IP
	 * @return 登录信息
	 */
	public LoginInfo buildLoginInfo(String username, String clientIp) {
		// 如果是超级用户
		if (this.isSuperUser(username)) {
			// 查询用户关联的角色
			final Set<IamRole> roles = new HashSet<>();
			// 查询用户关联的权限
			final Set<IamPerm> perms = new HashSet<>();

			// 填充数据
			permRepository.findAll().forEach(perms::add);
			roleRepository.findAll().forEach(roles::add);

			// 封装登录信息
			final LoginInfo loginInfo = LoginInfo.builder()
				.userId(0L)
				.clientIp(clientIp)
				.loginName(username)
				.displayName("超级管理员")
				.loginTime(timeService.getDateTime())
				.roles(roles.stream().map(IamRole::getRoleCode).collect(Collectors.toSet()))
				.menus(perms.stream().filter(IamPerm::isMenu).map(IamPerm::getPermCode).collect(Collectors.toSet()))
				.buttons(perms.stream().filter(IamPerm::isButton).map(IamPerm::getPermCode).collect(Collectors.toSet()))
				.resources(perms.stream().filter(IamPerm::isResource).map(IamPerm::getPermCode).collect(Collectors.toSet()))
				.authorities(perms.stream().filter(IamPerm::isAuthority).map(IamPerm::getPermCode).collect(Collectors.toSet()))
				.build();

			loginInfo.getMenus().add("*");
			loginInfo.getRoles().add("*");
			loginInfo.getButtons().add("*");
			loginInfo.getResources().add("*");
			loginInfo.getAuthorities().add("*");

			return loginInfo;
		}


		// 查询用户信息
		final IamUser iamUser = userRepository.findByUserName(username);

		// 设置最后登录时间
		iamUser.setLastLoginTime(timeService.getDateTime());
		userRepository.save(iamUser);

		// 查询用户关联的角色
		final Set<IamRole> roles = roleRepository.queryByUser(iamUser.getId());

		// 查询用户关联的权限
		final Set<IamPerm> perms = permRepository.queryByUser(iamUser.getId());

		// 封装登录信息
		return LoginInfo.builder()
			.clientIp(clientIp)
			.userId(iamUser.getId())
			.loginName(iamUser.getUserName())
			.displayName(iamUser.getUserShowName())
			.loginTime(iamUser.getLastLoginTime())
			.roles(roles.stream().map(IamRole::getRoleCode).collect(Collectors.toSet()))
			.menus(perms.stream().filter(IamPerm::isMenu).map(IamPerm::getPermCode).collect(Collectors.toSet()))
			.buttons(perms.stream().filter(IamPerm::isButton).map(IamPerm::getPermCode).collect(Collectors.toSet()))
			.resources(perms.stream().filter(IamPerm::isResource).map(IamPerm::getPermCode).collect(Collectors.toSet()))
			.authorities(perms.stream().filter(IamPerm::isAuthority).map(IamPerm::getPermCode).collect(Collectors.toSet()))
			.build();
	}

	/**
	 * 判断是否为超级用户
	 *
	 * @param username 用户名
	 * @return true 表示是超级用户
	 */
	private boolean isSuperUser(String username) {
		return StringUtils.equals(securityProperties.getSuperUsername(), username);
	}
}
